#!/bin/bash
###
# @Author: Logan.Li
# @Date: 2025-09-09 01:28:00
# @LastEditTime: 2025-10-20 23:21:09
# @Description: OpenVPN服务安装脚本
# @支持系统: CentOS 7/8/9, Ubuntu 18.04/20.04/22.04/24.04
###
# 使用方法:
# curl -s https://gitee.com/attacker/All-In-One-Ops/raw/master/1.scripts/services/openvpn.sh | bash

# 基础设置
set -e  # 遇到错误立即退出

# 简洁输出函数
info() { echo -e "\e[34m[INFO]\e[0m $1"; }
warn() { echo -e "\e[33m[WARN]\e[0m $1"; }
error() { echo -e "\e[31m[ERROR]\e[0m $1" >&2; }
success() { echo -e "\e[32m[SUCCESS]\e[0m $1"; }

# 检查是否为root权限
check_root() {
    if [ $(id -u) -ne 0 ]; then
        error "此脚本必须以root权限运行！"
        exit 1
    fi
}

# 检测操作系统
detect_os() {
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS=$ID
        OS_VERSION=$VERSION_ID
        info "检测到系统: $NAME $VERSION_ID"
    else
        error "无法检测操作系统版本"
        exit 1
    fi

    # 验证系统是否支持
    case $OS in
        centos|rhel|rocky|almalinux)
            if [[ ! "$OS_VERSION" =~ ^[7-9] ]]; then
                error "仅支持 CentOS/RHEL 7/8/9"
                exit 1
            fi
            PKG_MANAGER="yum"
            ;;
        ubuntu|debian)
            PKG_MANAGER="apt"
            ;;
        *)
            error "不支持的操作系统: $OS"
            error "仅支持: CentOS 7/8/9, Ubuntu 18.04+"
            exit 1
            ;;
    esac
    success "系统检测通过"
}

# 获取服务器外网IP
get_server_ip() {
    SERVER_IP=$(curl -s ifconfig.me || curl -s icanhazip.com || curl -s ipinfo.io/ip)
    if [ -z "$SERVER_IP" ]; then
        warn "无法自动获取服务器IP，请手动输入："
        read -p "请输入服务器IP地址: " SERVER_IP
    fi
    info "服务器IP: $SERVER_IP"
}



# 主安装流程
main() {
    check_root
    detect_os
    get_server_ip

    info "开始安装OpenVPN..."

    # 停止并清理旧的OpenVPN
    info "清理旧的OpenVPN配置..."
    systemctl stop openvpn@server 2>/dev/null || true
    pkill openvpn 2>/dev/null || true

    if [ "$PKG_MANAGER" = "yum" ]; then
        # CentOS/RHEL系统
        yum remove openvpn -y 2>/dev/null || true
        rm -rf /etc/openvpn
        
        info "安装OpenVPN及依赖..."
        yum install -y epel-release 2>/dev/null || true
        yum install -y openvpn openssl wget tar
    else
        # Ubuntu/Debian系统
        apt-get remove --purge openvpn -y 2>/dev/null || true
        rm -rf /etc/openvpn
        
        info "安装OpenVPN及依赖..."
        apt-get update
        apt-get install -y openvpn openssl wget tar
    fi

    # 验证安装
    if ! command -v openvpn &> /dev/null; then
        error "OpenVPN安装失败！"
        exit 1
    fi
    success "OpenVPN安装成功: $(openvpn --version | head -n1)"

    # 创建OpenVPN目录
    mkdir -p /etc/openvpn/client
    cd /etc/openvpn

    # 下载证书包
    info "下载证书和认证脚本..."
    if ! curl -fsSL -O --max-time 10 --retry 3 --retry-delay 5 \
        https://gitee.com/attacker/All-In-One-Ops/raw/master/1.scripts/services/openvpn.tar.gz; then
        error "证书包下载失败！"
        exit 1
    fi

    tar zxf openvpn.tar.gz
    chmod +x checkpwd.sh 2>/dev/null || warn "checkpwd.sh不存在，跳过权限设置"

    # 配置OpenVPN服务器
    configure_server
    
    # 配置系统转发
    configure_forwarding
    
    # 启动服务
    start_service
    
    # 生成客户端配置
    generate_client_config
    
    success "OpenVPN服务器安装完成！"
    
    # 显示账号信息和配置文件位置
    show_account_info
}

# 配置OpenVPN服务器
configure_server() {
    info "生成服务器配置文件..."
    
    # 创建openvpn用户（如果不存在）
    if ! id openvpn &>/dev/null; then
        useradd -r -s /sbin/nologin openvpn
    fi

##### openvpn配置文件 #####
    cat >/etc/openvpn/server.conf <<'SERVERCONF'
user openvpn
group openvpn

# 选择协议和端口
proto tcp  # 支持TCP/UDP
port 1194  # 服务器监听端口

# VPN通道类型
dev tun    # 支持创建TUN路由IP通道或TAP以太网通道

# 保持连接
keepalive 10 120  # 保持连接的时间，默认为30秒
max-clients 1000 # 设置最大的客户端用户数，没有这句则默认无限

# 持久性设置
persist-key  # 通过keepalive检测超时后，重新启动VPN，不重新读取keys，保留第一次使用的keys
persist-tun  # 检测超时后，重新启动VPN，一直保持TUN是linkup的。否则网络会先linkdown然后再linkup
duplicate-cn # 允许多个客户端使用相同的公共证书登录

# 证书和认证设置
ca ca.crt
cert server.crt
key server.key
dh dh.pem

# 用户名和密码方式登录
script-security 3
verify-client-cert none
username-as-common-name
auth-user-pass-verify /etc/openvpn/checkpwd.sh via-env

ifconfig-pool-persist ipp.txt 
server 10.8.0.0 255.255.255.0  # VPN客户端网段
#push "dhcp-option DNS 223.5.5.5"  # 下发dns

# 下发路由
#push "route 192.168.0.0 255.255.255.0 vpn_gateway"  # 下发指定路由
push "redirect-gateway def1"  # 下发默认路由

# 日志设置
verb 3
log /etc/openvpn/openvpn.log
log-append /etc/openvpn/openvpn.log
status /etc/openvpn/openvpn-status.log

SERVERCONF

    touch openvpn-password.log
    
    # 创建密码文件
    cat >/etc/openvpn/psw-file <<'PSWFILE'
admin vpnpass
PSWFILE

    # 设置权限
    chown -R openvpn:openvpn /etc/openvpn 2>/dev/null || \
        chown -R openvpn:openvpn /etc/openvpn
    chmod 600 /etc/openvpn/psw-file
    
    success "服务器配置文件生成完成"
}

# 配置系统转发
configure_forwarding() {
    info "配置IP转发和NAT..."

    # 启用IP转发
    echo 1 > /proc/sys/net/ipv4/ip_forward
    
    if ! grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf; then
        echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
    fi
    sysctl -p > /dev/null 2>&1
    
    # 配置iptables NAT转发
    if ! iptables -t nat -C POSTROUTING -j MASQUERADE 2>/dev/null; then
        iptables -t nat -I POSTROUTING -j MASQUERADE
    fi
    
    # 保存iptables规则
    if [ "$PKG_MANAGER" = "yum" ]; then
        service iptables save 2>/dev/null || true
    else
        # Ubuntu使用iptables-persistent
        if ! dpkg -l | grep -q iptables-persistent; then
            DEBIAN_FRONTEND=noninteractive apt-get install -y iptables-persistent
        fi
        netfilter-persistent save 2>/dev/null || true
    fi
    
    success "IP转发和NAT配置完成"
}

# 启动服务
start_service() {
    info "启动OpenVPN服务..."

    systemctl daemon-reload
    systemctl enable openvpn@server
    systemctl restart openvpn@server
    
    # 检查服务状态
    sleep 2
    if systemctl is-active --quiet openvpn@server; then
        success "OpenVPN服务启动成功"
    else
        error "OpenVPN服务启动失败！"
        systemctl status openvpn@server --no-pager
        exit 1
    fi
}

# 生成客户端配置
generate_client_config() {
    info "生成客户端配置文件..."
    cat >/etc/openvpn/client/client.ovpn <<CLIENTCONF
client
dev tun   # 支持创建tun路由ip通道或tap以太网通道
port 1194 # 服务器监听端口
proto tcp # 支持TCP/udp
remote $SERVER_IP # vpn服务器地址

# 客户端路由配置（服务端已下发默认路由）

# 断线自动重新连
resolv-retry infinite

auth-nocache    # 密码不存内存
auth-user-pass  # 输入密码认证
#auth-user-pass pass.txt # 保存自动登录密码

remote-cert-tls server
verb 3

# 内嵌CA证书
<ca>
-----BEGIN CERTIFICATE-----
MIIE3zCCA8egAwIBAgIJAK7JOfbBfW4LMA0GCSqGSIb3DQEBCwUAMIGgMQswCQYD
VQQGEwJDTjERMA8GA1UECAwIWmhlamlhbmcxETAPBgNVBAcMCEhhbmdaaG91MRMw
EQYDVQQKDApvcHNiYXNlLmNuMRwwGgYDVQQLDBNPcmdhbml6YXRpb25hbCBVbml0
MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTEiMCAGCSqGSIb3DQEJARYTYWRtaW5AYXR0
YWNrZXIuY2x1YjAgFw0yMDEwMTExOTA2NDhaGA8yMTE5MDkxODE5MDY0OFowgaAx
CzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8GA1UEBwwISGFuZ1po
b3UxEzARBgNVBAoMCm9wc2Jhc2UuY24xHDAaBgNVBAsME09yZ2FuaXphdGlvbmFs
IFVuaXQxFDASBgNVBAMMC0Vhc3ktUlNBIENBMSIwIAYJKoZIhvcNAQkBFhNhZG1p
bkBhdHRhY2tlci5jbHViMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
w+MYAwrY48Mi29vdz0Ss+VK0N7sm7HKZMUoUSEJwYJ8v1Co4D17SkeFcfr2OarRN
zY7yk5KL/CnQSnstkVqvwiI5u1FxKuebjsWsTpBzgFituh2ued6JupTyoeFxRaL7
MkHyWRPbGzCwk5iwobVRyx7T2YsqMx+fvLQQFK1ThkOySTtqdTgUpLlfIaPFiVnp
PaWHk71eGbP8t2DDaHCukg2mLNMkxoyd8kkdpAaQaRVM5YGPylXNf0O3jO0oYyBL
AxlsgmN2xvxdhv8wNMZT8/SE7XO7GAaeKRom5u1MRYNdV6wQFmJDO7FWgM+L3JWU
hhIH7M/wkREynoJ4GeWZxQIDAQABo4IBFjCCARIwHQYDVR0OBBYEFE5ZeqQemSmf
31X+xN3+WaO/2umLMIHVBgNVHSMEgc0wgcqAFE5ZeqQemSmf31X+xN3+WaO/2umL
oYGmpIGjMIGgMQswCQYDVQQGEwJDTjERMA8GA1UECAwIWmhlamlhbmcxETAPBgNV
BAcMCEhhbmdaaG91MRMwEQYDVQQKDApvcHNiYXNlLmNuMRwwGgYDVQQLDBNPcmdh
bml6YXRpb25hbCBVbml0MRQwEgYDVQQDDAtFYXN5LVJTQSBDQTEiMCAGCSqGSIb3
DQEJARYTYWRtaW5AYXR0YWNrZXIuY2x1YoIJAK7JOfbBfW4LMAwGA1UdEwQFMAMB
Af8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBCwUAA4IBAQBaFL8EbJx+H+l7bURs
ehlgl685/A8RS/3MoNr716R0Kk2qtDiuqiFq7fBP5YCn7ozhFXhNMsJdSwq87DpC
4WXq8qh/YZNHT0d9ALP1N7YWAKtajqPeHKTuaiNVeEzKpmYBGao9tSxs3CKfCaQS
0S/CBQV9osr5OGiTEZfANCNsWwNs+0/IqpwzevQtvYq4u42M58KJF0n4nmG9NJ69
CbcwTr95IVWdH1Uj80g420tCPdIRLS3EYqP4YXz1BSpVEETgULO4w725gGXsVIYc
mEGTvkjxXBJLzM8tOkyv3PpMe4PsQMtK/62GJhSB9Bwt5c/3sWAmr+EjPLVV8LW1
sYuH
-----END CERTIFICATE-----
</ca>
CLIENTCONF

    success "客户端配置文件已生成: /etc/openvpn/client/client.ovpn"

    # 创建单独的ca.crt文件（兼容性）
    if [ -f /etc/openvpn/ca.crt ]; then
        cp /etc/openvpn/ca.crt /etc/openvpn/client/
    fi
}

# 显示账号信息和配置文件位置
show_account_info() {
    echo ""
    echo "=================================================="
    echo ""
    
    # 读取账号信息
    if [ -f /etc/openvpn/psw-file ]; then
        # 读取第一行账号信息
        ACCOUNT_LINE=$(head -n1 /etc/openvpn/psw-file)
        USERNAME=$(echo "$ACCOUNT_LINE" | awk '{print $1}')
        PASSWORD=$(echo "$ACCOUNT_LINE" | awk '{print $2}')
    else
        USERNAME="admin"
        PASSWORD="vpnpass"
    fi
    
    success "🔑 VPN账号信息文件位置:"
    echo ""
    echo "   📁 /etc/openvpn/psw-file"
    echo ""
    echo "   👤 用户名: $USERNAME"
    echo ""
    echo "   🔒 密码: $PASSWORD"
    echo ""
    echo ""
    
    success "📥 下载客户端配置文件:"
    echo ""
    echo "   📋 scp root@$SERVER_IP:/etc/openvpn/client/client.ovpn ./"
    echo ""
    echo "   📋 或者直接复制 /etc/openvpn/client/client.ovpn 文件内容"
    echo ""
    echo "=================================================="
    echo ""
}

# 执行主函数
main
